class Kvue {
  constructor(options) {
    this.$options = options
    this.$data = options.data
    this.observer(this.$data)

    new Compile(options.el, this)
    options.created && options.created.call(this)
  }
  // 拦截传入的data并转换使用方式，去除$
  observer(obj) {
    if (!obj || typeof obj !== 'object') return false
    Object.keys(obj).forEach(key => {
      this.defineReactive(obj, key, obj[key])
      this.proxyData(key)
    })
  }
  // 将传入的data属性全部设置监听
  defineReactive(obj, key, val) {
    this.observer(val) // 递归将传入的data全部设置监听
    const dep = new Dep()

    Object.defineProperty(obj, key, {
      get() {
        Dep.target && dep.addWatcher(Dep.target)
        return val
      },
      set(newVal) {
        if (newVal !== val) val = newVal
        dep.notify()
      }
    })
  }
  // 代理data，有问题的代码，不能兼容层级对象
  proxyData(key) {
    Object.defineProperty(this, key, {
      get: () => this.$data[key],
      set(newVal) {
        this.$data[key] = newVal
      }
    })
  }
}

// 创建dep类，管理所有的监听器，订阅/发布（pub/sub，观察者）模式
class Dep {
  constructor() {
    this.watchers = []
  }
  // 添加监听器
  addWatcher(watcher) {
    this.watchers.push(watcher)
  }
  // 统一发布，有性能问题，更新得还是不够精细，如果能知道更新哪个字段就好了，这样就不会浪费资源了
  notify() {
    this.watchers.forEach(watcher => watcher.update())
  }
}
// 创建监视器类，监听虚拟dom
class Watcher {
  constructor(vm, key, cb) {
    this.vm = vm
    this.key = key
    this.cb = cb

    Dep.target = this
    this.vm[this.key] // 触发get方法，进行依赖收集
    Dep.target = null
  }
  update() {
    this.cb.call(this.vm, this.vm[this.key])
    console.log(this.key + '更新了!');
  }
}
